# Appendix Replication File
# Trojan Horses in Liberal International Organizations?:
# How Democratic Backsliders Undermine the UNHRC
# September 2023

# load packages
library(vdemdata)
library(ggplot2)
library(dplyr)
library(RColorBrewer)
library(stargazer)
library(nnet)
library(AER)
library(broom)
library(MASS)
library(sandwich)
library(lmtest)
library(topicmodels)
library(readtext)
library(stm)

# Appendix Figure A1: Democratic trajectories of backsliding members of the UNHRC, 1985–2021
rm(list=ls())
load("unhrc_regression_data.RData")

# create list of backsliding states in UNHRC, 2006-2021
db <- subset(unhrc_regress, unhrc_regress$db_bin_democracies == 1)
list(unique(sort(db$votingstate)))

# load V-Dem data from vdemdata package
vdem <- vdem

# subset to backsliding countries only
plot <- subset(vdem, country_name == "Hungary"| country_name == "Poland"| country_name == "Ecuador"| 
                 country_name == "Nicaragua"| country_name == "Madagascar"| 
                 country_name =="Bolivia"| country_name == "Brazil"| country_name == "India"| 
                 country_name == "Ukraine" | country_name == "Bangladesh" | country_name == "Fiji" | 
                 country_name == "Philippines"| country_name == "Sri Lanka" | country_name == "Venezuela")

# plot democratic trajectories of backsliding UNHRC members

ggplot(plot, aes(year, v2x_polyarchy, linetype=as.factor(country_name), 
                     col = country_name)) + 
  geom_line(se=FALSE, size = 1) +
  scale_linetype_manual(values=c("twodash", "solid", "longdash", "dotted", "dotdash", 
                                 "dashed", "twodash", "solid", "longdash", "dotted", "dotdash",
                                 "twodash", "solid", "longdash"), 
                        name='', 
                        guide = guide_legend(keywidth=4, keyheight=2)) +
  scale_color_manual(values = c("#A6CEE3", "#1F78B4", "#B2DF8A", "#33A02C", "#FB9A99", 
    "#E31A1C", "#FDBF6F", "#FF7F00", "#CAB2D6", "#6A3D9A", "#B15928", "#666666", "#66C2A5", "#67001F"), 
                     name="",
                     guide = guide_legend(keywidth=5, keyheight=2)) +
  theme_bw() + 
  labs (x = "", y = "Electoral Democracy Index") +
  theme(axis.text.x=element_text(size = 18),
        axis.title.x = element_blank()) + 
  theme(axis.text.y=element_text(size = 18),
        axis.title.y = element_text(size = 20)) +
  theme(legend.text = element_text(size=14), legend.position = "bottom") +
  xlim(1985,2021) + 
  ylim(0,1) + 
  geom_vline(xintercept= 1995) 

# Appendix Table A2: UNHRC Model Descriptive Statistics ####
rm(list=ls())
load("unhrc_regression_data.RData")

stats <- subset(unhrc_regress, vote != 4) # remove obs with missing vote data
stats$vote <- as.numeric(stats$vote)

stats <- stats[,c("vote",
                  "db_bin_democracies",
                  "v2x_polyarchy_votingstate" ,
                  "Israel" , 
                  "Syria", 
                  "v2x_polyarchy_targetstate" , 
                  "same_geo_region" , 
                  "vid_usagree" , 
                  "tid_usagree" , 
                  "vid_tid_unga_agree",
                  "tid_hr_score")]
vars <- c("Vote choice",
          "Backslide since 1995",
          "Voting EDI score",
          "Israel", 
          "Syria", 
          "Target EDI score", 
          "Voting and target in same region",
          "Voting UNGA US agree", 
          "Target UNGA US agree", 
          "Target-voting UNGA affinity",
          "Target state HR score")

library(stargazer)
stargazer(stats, covariate.labels = vars, 
          title = "Descriptive Statistics: Voting in the UNHRC, 2006--2021", 
          font.size = "footnotesize", digits = 2,  
          table.placement = "H", label = "tab:descriptive_unhrc")

# Appendx Table A3: Autocratization and vote choice in the UNHRC, 2006–2021 ####
rm(list=ls())
load("unhrc_regression_data.RData")

# drop obs where vote == 4 (missing)
mod <- subset(unhrc_regress, vote != 4)

# set baseline level of dv ('yes' vote) and relevel
mod$vote <- ifelse(mod$vote == "1", "no", mod$vote)
mod$vote <- ifelse(mod$vote == "2", "abstain", mod$vote)
mod$vote <- ifelse(mod$vote == "3", "yes", mod$vote)
mod$dv <- as.factor(mod$vote)

# reference category 
mod$dv <- relevel(mod$dv, ref = "yes")

tabA3.mod1 <- multinom(dv ~ autocratization_bin + 
                                 v2x_polyarchy_votingstate +
                                 Israel + 
                                 Syria + 
                                 v2x_polyarchy_targetstate + 
                                 same_geo_region + 
                                 vid_usagree + 
                                 tid_usagree + 
                                 vid_tid_unga_agree + 
                                 tid_hr_score +
                                 factor(year), data = mod)

# clustered standard errors 
se.tabA3.mod1 <- coeftest(tabA3.mod1, vcov = vcov(tabA3.mod1, type = "HC0", cluster = mod$vid))

# relative risk ratios
exp(coef(tabA3.mod1))

# Appendix Table A4: Democratic backsliding and vote choice in the UNHRC, 2006–2021, Continuous Measure of Democratic Backsliding ####
rm(list=ls())
load("unhrc_regression_data.RData")

# drop obs where vote == 4 (missing)
mod <- subset(unhrc_regress, vote != 4)

# set baseline level of dv ('yes' vote) and relevel
mod$vote <- ifelse(mod$vote == "1", "no", mod$vote)
mod$vote <- ifelse(mod$vote == "2", "abstain", mod$vote)
mod$vote <- ifelse(mod$vote == "3", "yes", mod$vote)
mod$dv <- as.factor(mod$vote)

# reference category 
mod$dv <- relevel(mod$dv, ref = "yes")

tabA4.mod1 <- multinom(dv ~ db_continuous + 
                                 v2x_polyarchy_votingstate +
                                 Israel + 
                                 Syria + 
                                 v2x_polyarchy_targetstate + 
                                 same_geo_region + 
                                 vid_usagree + 
                                 tid_usagree + 
                                 vid_tid_unga_agree + 
                                 tid_hr_score +
                                 factor(year), data = mod)

# clustered standard errors 
se.tabA4.mod1 <- coeftest(tabA4.mod1, vcov = vcov(tabA4.mod1, type = "HC0", cluster = mod$vid))

# relative risk ratios
exp(coef(tabA4.mod1))

# Appendix Table A5: Democratic backsliding and vote choice in the UNHRC, 2006–2021, GDP and Region FE ####
rm(list=ls())
load("unhrc_regression_data.RData")

# drop obs where vote == 4 (missing)
mod <- subset(unhrc_regress, vote != 4)

# set baseline level of dv ('yes' vote) and relevel
mod$vote <- ifelse(mod$vote == "1", "no", mod$vote)
mod$vote <- ifelse(mod$vote == "2", "abstain", mod$vote)
mod$vote <- ifelse(mod$vote == "3", "yes", mod$vote)
mod$dv <- as.factor(mod$vote)

# reference category 
mod$dv <- relevel(mod$dv, ref = "yes")

tabA5.mod1 <- multinom(dv ~ db_bin_democracies + 
                         v2x_polyarchy_votingstate +
                         Israel + 
                         Syria +
                         v2x_polyarchy_targetstate + 
                         same_geo_region + 
                         vid_usagree + 
                         tid_usagree + 
                         vid_tid_unga_agree + 
                         tid_hr_score +
                         vid_gdp_pc + 
                         factor(year) + factor(un_region_votingstate), data = mod)

# clustered standard errors 
se.tabA5.mod1 <- coeftest(tabA5.mod1, vcov = vcov(tabA5.mod1, type = "HC0", cluster = mod$vid))

# relative risk ratios
exp(coef(tabA5.mod1))

# Appendix Figure A2: Distribution of EDI score of UPR recommending state by year ####
rm(list=ls())
load("upr_regression_data.RData")

upr_regress %>%
  group_by(year) %>%
  mutate(mean_poly = mean(v2x_polyarchy_recommending_state, na.rm = T)) %>%
  dplyr::select(mean_poly, v2x_polyarchy_recommending_state, year) %>%
  ungroup() %>%
ggplot(aes(x = factor(year), y = v2x_polyarchy_recommending_state)) + 
  geom_boxplot() + 
  stat_summary(fun = mean,
               geom = "line",
               aes(group = 1),
               col = "red") + 
  theme_bw() + 
  xlab("") + 
  ylab("Electoral Democracy Index") + 
  theme(text = element_text(size=20))

# Appendix Table A6: Descriptive Statistics: UPR Reports of Advanced Democracies ####
rm(list=ls())
load("upr_regression_data.RData")

# subset to only include obs where advanced democracy is under review & reviewer is not adv demo
stats <- subset(upr_regress, upr_regress$advanced_demo_state_under_review == 1 & 
                   upr_regress$advanced_demo_rec_state == 0)

stats <- stats[,c("dv_count_issues_per_review" ,
                  "db_bin_democracies",
                  "v2x_polyarchy_recommending_state" , 
                  "v2x_polyarchy_state_under_review" , 
                  "same_geo_region" , 
                  "usagree_recommending_state" , 
                  "usagree_state_under_review" , 
                  "review_recommend_unga_agree",
                  "hr_score_state_under_review", 
                  "recommending_under_review")]
stats <- as.data.frame(stats)
vars <- c("Number of issues per review",
          "Backslide since 1995",
          "Recommend EDI score",
          "State under review EDI score", 
          "Same region",
          "Recommend UNGA US agree", 
          "State under review UNGA US agree", 
          "Recommend-under review UNGA affinity",
          "State under review HR score", 
          "Recommending state under review")

library(stargazer)
stargazer(stats, covariate.labels = vars, 
          title = "Descriptive Statistics: UPR Reports of Advanced Democracies", 
          font.size = "footnotesize", digits = 2,  
          table.placement = "H", label = "tab:descriptive_upr_issues")

# Appendix Table A7: UPR Issues Identified against Advanced Democracies, 2008–2020, Continuous Measure of Democratic Backsliding ####
rm(list=ls())
load("upr_regression_data.RData")

# subset to only include obs where advanced democracy is under review & reviewer is not adv demo
mod <- subset(upr_regress, upr_regress$advanced_demo_state_under_review == 1 & 
                   upr_regress$advanced_demo_rec_state == 0)

# model 1: all reports 
tabA7.mod1 <- glm(dv_count_issues_per_review ~ db_continuous  + 
                                  v2x_polyarchy_recommending_state + 
                                  v2x_polyarchy_state_under_review + 
                                  same_geo_region + 
                                  usagree_recommending_state + 
                                  usagree_state_under_review + 
                                  review_recommend_unga_agree +
                                  hr_score_state_under_review +  
                                  recommending_under_review + 
                                  factor(year), 
                                family = "quasipoisson",
                                data = mod)

# model 1 clustered standard errors
(se.tabA7.mod1 <- coeftest(tabA7.mod1, vcov = vcovHC(tabA7.mod1,type = "HC0", 
                                                   cluster = mod$ccode_recommending_state)))

# model 2: reports by UNHRC members

# subset to only include observations where reviewer is UNHRC member
mod2 <- subset(mod, mod$unhrc_member_recommending_state == 1)

tabA7.mod2 <- glm(dv_count_issues_per_review ~ db_continuous  + 
                                  v2x_polyarchy_recommending_state + 
                                  v2x_polyarchy_state_under_review + 
                                  same_geo_region + 
                                  usagree_recommending_state + 
                                  usagree_state_under_review + 
                                  review_recommend_unga_agree +
                                  hr_score_state_under_review +  
                                  recommending_under_review + 
                                  factor(year), 
                                family = "quasipoisson",
                                data = mod2)

# model 2 clustered standard errors
(se.tabA7.mod2 <- coeftest(tabA7.mod2, vcov = vcovHC(tabA7.mod2,type = "HC0", 
                                                   cluster = mod2$ccode_recommending_state)))

# Appendix Table A8: UPR Issues Identified against Advanced Democracies, 2008–2020, Relative Power ####
rm(list=ls())
load("upr_regression_data.RData")

# subset to only include obs where advanced democracy is under review & reviewer is not adv demo
mod <- subset(upr_regress, upr_regress$advanced_demo_state_under_review == 1 & 
                   upr_regress$advanced_demo_rec_state == 0)

# model 1 - all reports
tabA8.mod1 <- glm(dv_count_issues_per_review ~ db_bin_democracies +
                                  v2x_polyarchy_recommending_state + 
                                  v2x_polyarchy_state_under_review + 
                                  same_geo_region + 
                                  usagree_recommending_state + 
                                  usagree_state_under_review + 
                                  review_recommend_unga_agree +
                                  hr_score_state_under_review + 
                                  recommending_under_review + 
                                  cinc_rec_state + 
                                  cinc_state_under_review +
                                  factor(year), 
                                family = "quasipoisson",
                                data = mod)

# model 1 clustered standard errors
(se.tabA8.mod1 <- coeftest(tabA8.mod1, vcov = vcovHC(tabA8.mod1,type = "HC0", 
                                                   cluster = mod$ccode_recommending_state)))

# model 2: reports by UNHRC members

# subset to only include observations where reviewer is UNHRC member
mod2 <- subset(mod, mod$unhrc_member_recommending_state == 1)

tabA8.mod2 <- glm(dv_count_issues_per_review ~ db_bin_democracies +
                                  v2x_polyarchy_recommending_state + 
                                  v2x_polyarchy_state_under_review + 
                                  same_geo_region + 
                                  usagree_recommending_state + 
                                  usagree_state_under_review + 
                                  review_recommend_unga_agree +
                                  hr_score_state_under_review + 
                                  recommending_under_review + 
                                  cinc_rec_state + 
                                  cinc_state_under_review +
                                  factor(year), 
                                family = "quasipoisson",
                                data = mod2)

# model 2 clustered standard errors
(se.tabA8.mod2 <- coeftest(tabA8.mod2, vcov = vcovHC(tabA8.mod2,type = "HC0", 
                                                   cluster = mod2$ccode_recommending_state)))

# Appendix Table A9: UPR Issues Identified against Advanced Democracies, 2008–2020, GDP and Region FE ####
rm(list=ls())
load("upr_regression_data.RData")

# subset to only include obs where advanced democracy is under review & reviewer is not adv demo
mod <- subset(upr_regress, upr_regress$advanced_demo_state_under_review == 1 & 
                   upr_regress$advanced_demo_rec_state == 0)

# model 1 - all reports
tabA9.mod1 <- glm(dv_count_issues_per_review ~ db_bin_democracies +
                                  v2x_polyarchy_recommending_state + 
                                  v2x_polyarchy_state_under_review + 
                                  same_geo_region + 
                                  usagree_recommending_state + 
                                  usagree_state_under_review + 
                                  review_recommend_unga_agree +
                                  hr_score_state_under_review + 
                                  recommending_under_review + 
                                  recommend_gdp_pc +
                                  factor(year) + factor(recommend_un_region), 
                                family = "quasipoisson",
                                data = mod)

# model 1 clustered standard errors
(se.tabA9.mod1 <- coeftest(tabA9.mod1, vcov = vcovHC(tabA9.mod1,type = "HC0", 
                                                   cluster = mod$ccode_recommending_state)))

# model 2: reports by UNHRC members

# subset to only include observations where reviewer is UNHRC member
mod2 <- subset(mod, mod$unhrc_member_recommending_state == 1)

tabA9.mod2 <- glm(dv_count_issues_per_review ~ db_bin_democracies +
                                  v2x_polyarchy_recommending_state + 
                                  v2x_polyarchy_state_under_review + 
                                  same_geo_region + 
                                  usagree_recommending_state + 
                                  usagree_state_under_review + 
                                  review_recommend_unga_agree +
                                  hr_score_state_under_review + 
                                  recommending_under_review + 
                                  recommend_gdp_pc +
                                  factor(year) + factor(recommend_un_region), 
                                family = "quasipoisson",
                                data = mod2)

# model 2 clustered standard errors
(se.tabA9.mod2 <- coeftest(tabA9.mod2, vcov = vcovHC(tabA9.mod2,type = "HC0", 
                                                   cluster = mod2$ccode_recommending_state)))

# STM Topic Figure and Excerpts ####

# Appendix Figure A3: STM Topic Number Selection ####
rm(list=ls())
load("upr_stm_data.RData")

# pre-process and clean data
# drop observations with missing covariates
upr_stm <- subset(upr_stm, !is.na(upr_stm$db_bin_democracies))
upr_stm <- subset(upr_stm, !is.na(upr_stm$ccode_recommending_state))
upr_stm <- subset(upr_stm, !is.na(upr_stm$v2x_polyarchy_recommending_state))
upr_stm <- subset(upr_stm, !is.na(upr_stm$v2x_polyarchy_state_under_review))
upr_stm <- subset(upr_stm, !is.na(upr_stm$same_geo_region))
upr_stm <- subset(upr_stm, !is.na(upr_stm$usagree_recommending_state))
upr_stm <- subset(upr_stm, !is.na(upr_stm$usagree_state_under_review))
upr_stm <- subset(upr_stm, !is.na(upr_stm$hr_score_state_under_review))
upr_stm <- subset(upr_stm, !is.na(upr_stm$recommending_under_review))
upr_stm <- subset(upr_stm, !is.na(upr_stm$review_recommend_unga_agree))

# create corpus
processed <- textProcessor(upr_stm$recommendations, metadata = upr_stm)
out <- prepDocuments(processed$documents, processed$vocab, processed$meta)
docs <- out$documents
vocab <- out$vocab
meta <- out$meta

# Determine number of topics 
tmulti <- manyTopics(out$documents, out$vocab, 
                     K = 2:20, prevalence = ~ db_bin_democracies,
                     max.em.its = 10, 
                     runs = 5, data = out$meta, seed = 1234)

t <- tmulti$semcoh
s <- tmulti$exclusivity
sc <- c()
ex <- c()
cols <- c()
for(i in 1:19){
  sc <- c(sc, mean(t[[i]]))
  ex <- c(ex, mean(s[[i]]))
  cols <- c(2:20)
}
pex <- data.frame(cbind(sc, ex, cols))
pex$cols <- as.factor(pex$cols)

# Plot semantic coherence and exclusivity for each topic (Appendix Figure A3)
ggplot(pex, aes(x = sc, y = ex, colour = cols, label = cols)) + 
  geom_point(alpha = 1/20) + 
  geom_text(hjust=0, vjust=0,  size = 5) + 
  theme_bw() +
  xlab("Semantic coherence") + 
  ylab("Exclusivity") + 
  theme(legend.position = "none") +
  theme(text = element_text(size = 20))


# Appendix 12: STM Sample Excerpts ####
# estimate model with 6 topics
stm <- stm(docs, vocab, K = 6, 
                    prevalence = ~ db_bin_democracies + 
                      v2x_polyarchy_recommending_state + 
                      v2x_polyarchy_state_under_review + 
                      same_geo_region + 
                      usagree_recommending_state + 
                      usagree_state_under_review + 
                      review_recommend_unga_agree +
                      hr_score_state_under_review + 
                      recommending_under_review + factor(year),
                      max.em.its=200, data=out$meta, init.type="Spectral", 
                      seed=84581)

# view excerpts for each topic
oo_1 <- findThoughts(stm, texts = meta$recommendations, topics=1, n=15) # human development
oo_1$docs

oo_2 <- findThoughts(stm, texts = meta$recommendations, topics=2, n=15) # ratify international HR conventions
oo_2$docs

oo_3 <- findThoughts(stm, texts = meta$recommendations, topics=3, n=15) # Women and LGBTQ+ rights
oo_3$docs

oo_4 <- findThoughts(stm, texts = meta$recommendations, topics=4, n=15) # Civil and political liberties 
oo_4$docs

oo_5 <- findThoughts(stm, texts = meta$recommendations, topics=5, n=15) # Estimation national HR institutions
oo_5$docs

oo_6 <- findThoughts(stm, texts = meta$recommendations, topics=6, n=15) # Protect minorities and vulnerable groups
oo_6$docs

